package com.jueling.culture.util;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.util.DigestUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;

/**
 *
 * @author linp
 * @date 2020/04/16
 *
 */
@Slf4j
@SuppressWarnings("all")
public class EncryptionUtil {
	private EncryptionUtil(){}
	private static final String ALGORITHM = "DES";
	public static final String KEY_ALGORITHM = "RSA";
	private final static String DEFAULT_CHART_SET = "utf-8";

	/**
	 * Get Des Key
	 */
	public static byte[] getKey() throws Exception {
		KeyGenerator keygen = KeyGenerator.getInstance(ALGORITHM);
		SecretKey deskey = keygen.generateKey();
		return deskey.getEncoded();
	}

	/**
	 * MD5
	 */
	public static byte[] md5(byte[] input) throws Exception {
		java.security.MessageDigest alg = java.security.MessageDigest
				.getInstance("MD5"); // or "SHA-1"
		alg.update(input);
		return alg.digest();
	}

	/**
	 * Convert byte[] to String
	 */
	public static String byte2hex(byte[] b) {
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			stmp = Integer.toHexString(b[n] & 0XFF);
			if (stmp.length() == 1) {
				hs = hs + "0" + stmp;
			} else {
				hs = hs + stmp;
			}
		}
		return hs.toUpperCase();
	}

	public static byte[] hexToByte(String hex){
		int m = 0, n = 0;
		int byteLen = hex.length() / 2; // 每两个字符描述一个字节
		byte[] ret = new byte[byteLen];
		for (int i = 0; i < byteLen; i++) {
			m = i * 2 + 1;
			n = m + 1;
			int intVal = Integer.decode("0x" + hex.substring(i * 2, m) + hex.substring(m, n));
			ret[i] = Byte.valueOf((byte)intVal);
		}
		return ret;
	}

	/**
	 * RSA私钥加密
	 *
	 * @param data
	 * @param privKey
	 *            密钥
	 * @return byte[] 加密数据
	 */
	public static String rsaEncryptByPrivateKey(byte[] data, String privKey) throws Exception {
		try {
			byte[] key = Base64.decodeBase64(privKey);
			// 取得私钥
			PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
			KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
			// 生成私钥
			PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
			// 数据加密
			Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
			cipher.init(Cipher.ENCRYPT_MODE, privateKey);
			byte[] b = cipher.doFinal(data);
			return Base64.encodeBase64String(b);
		} catch (Exception e) {
			throw e;
		}
	}

	/**
	 * MD5加密
	 * @param plainText
	 * @return
	 * @throws Exception
	 */
	public static String md5Encryption(String plainText) throws Exception {
		String re_md5 = new String();
		try {
			byte[] b = md5(plainText.getBytes("ISO-8859-1"));
			re_md5 = byte2hex(b);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return re_md5;
	}

	/**
	 * aes-128 加密
	 * @param sSrc 加密字符串
	 * @param sKey 秘钥 16位
	 * @return
	 */
	public static String aesEncrypt(String sSrc, String sKey)  {


		try {
			byte[] raw = sKey.getBytes(DEFAULT_CHART_SET);
			SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "AES");
			byte[] initParam = "16-Bytes--String".getBytes();
			IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			cipher.init(1, secretKeySpec, ivParameterSpec);
			byte[] encrypted = cipher.doFinal(sSrc.getBytes(DEFAULT_CHART_SET));
			//此处使用BASE64做转码功能
			return byte2hex(Base64.encodeBase64(encrypted));
		} catch (Exception e) {
			log.error(e.getMessage());
		}
		return null;

	}

	/**
	 * ase-128解密
	 * @param sSrc 解密字符串
	 * @param sKey 秘钥16位
	 * @return
	 */
	public static String aseDecrypt(String sSrc, String sKey) {
		try {
			byte[] ret = hexToByte(sSrc);
			byte[] byteContent = Base64.decodeBase64(ret);
			byte[] enCodeFormat = sKey.getBytes();
			SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
			byte[] initParam = "16-Bytes--String".getBytes();
			IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			cipher.init(2, secretKeySpec, ivParameterSpec);
			byte[] encryptedBytes = cipher.doFinal(byteContent);
			return new String(encryptedBytes, DEFAULT_CHART_SET);
		} catch (Exception ex) {
			log.error(ex.getMessage());
			return null;
		}
	}

	/**
	 * MD5
	 * @param key
	 * @param random
	 * @return
	 */
	public static String getMd5ByKey(String key,String random) {
		String temp = key + random;
		byte[] bytes = temp.getBytes();
		return DigestUtils.md5DigestAsHex(bytes);
	}

	/**
	 * MD5
	 * @param source
	 * @return
	 */
	public static String getMd5ByByte(byte[] source) {
		String s = null;
		char hexDigits[] = { // 用来将字节转换成 16 进制表示的字符
				'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
		try {
			java.security.MessageDigest md = java.security.MessageDigest
					.getInstance("MD5");
			md.update(source);
			byte tmp[] = md.digest(); // MD5 的计算结果是一个 128 位的长整数，
			// 用字节表示就是 16 个字节
			char str[] = new char[16 * 2]; // 每个字节用 16 进制表示的话，使用两个字符，
			// 所以表示成 16 进制需要 32 个字符
			int k = 0; // 表示转换结果中对应的字符位置
			for (int i = 0; i < 16; i++) { // 从第一个字节开始，对 MD5 的每一个字节
				// 转换成 16 进制字符的转换
				byte byte0 = tmp[i]; // 取第 i 个字节
				str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字节中高 4 位的数字转换,>>>为逻辑右移，将符号位一起右移
				str[k++] = hexDigits[byte0 & 0xf]; // 取字节中低 4 位的数字转换
			}
			s = new String(str); // 换后的结果转换为字符串
		} catch (Exception e) {
			e.printStackTrace();
		}
		return s;
	}

}
